/*
 *  CLinkedList.h
 *  GETestRender
 *
 *  Created by Quoc Dung Chu on 20/07/11.
 *  Copyright 2011 Paris 6. All rights reserved.
 *
 */

#ifndef GE_LIST_H
#define GE_LIST_H

namespace game_engine {
	namespace core {
	//private:
		template<class T>
		struct SLKNode 
		{
			SLKNode* Next;
			SLKNode* Prev;
			T Element;
			SLKNode(const T& e) : Next(0),Prev(0),Element(e){};
		};
	//public:
		template<class T>
		class CLinkedList  {
			//-------------------------------------------------------------------------------------
		private:
			SLKNode<T>* _begin;
			SLKNode<T>* _end;
			int _size;
			//-------------------------------------------------------------------------------------
		public:
			CLinkedList():_begin(0),_end(0),_size(0){}
			//-------------------------------------------------------------------------------------

			~CLinkedList()
			{
				clear();
			}
			//-------------------------------------------------------------------------------------

			void clear()
			{
				while (_begin) {
					SLKNode<T>* next = _begin->Next;
					delete _begin;
					_begin = next;
				}
				
				_end = 0;
				_size = 0;
			}
			//-------------------------------------------------------------------------------------

			bool empty() const
			{
				return _begin == 0;
			}
			//-------------------------------------------------------------------------------------
			void push_back(const T& element)
			{
				SLKNode<T>* node = new SLKNode<T>(element);
				
				++_size;
				
				if (_begin == 0) _begin = node;
				node->Prev = _end;
				if(_end != 0) _end->Next = node;
				_end = node;
			}
			//-------------------------------------------------------------------------------------
			void push_front(const T& element)
			{
				SLKNode<T>* node = new SLKNode<T>(element);
				++_size;
				if (_begin == 0)
				{
					_end = node;
					_begin = node;
				}
				else 
				{
					node->Next = _begin;
					_begin->Prev = node;
					_begin = node;
				}
			}
			//-------------------------------------------------------------------------------------
			void insert_after(SLKNode<T>* nodeTarget, const T& element)
			{
				SLKNode<T>* node = new SLKNode<T>(element);
				node->Next = nodeTarget->Next;
				if (nodeTarget->Next) nodeTarget->Next->Prev = node;
				node->Prev = nodeTarget;
				nodeTarget->Next = node;
				++_size;
				if (nodeTarget == _end) _end = node;
			}
			//-------------------------------------------------------------------------------------
			void insert_before(SLKNode<T>* nodeTarget, const T& element)
			{
				SLKNode<T>* node = new SLKNode<T>(element);
				node->Prev = nodeTarget->Prev;
				if(nodeTarget->Prev) nodeTarget->Prev->Next = node;
				node->Next = nodeTarget;
				nodeTarget->Prev = node;
				++_size;
				if (nodeTarget == _begin) _begin = node;
			}
			//-------------------------------------------------------------------------------------
			SLKNode<T>* erase(SLKNode<T>* node)
			{
				if ( !node 
					|| ( node->Prev == 0 && node != _begin ) 
					|| ( node->Next == 0 && node != _end))		return 0;
				
				SLKNode<T>* returnNode = node->Next;
				
				if ( node == _begin) 
				{
					_begin = node->Next;
				}
				else 
				{
					node->Prev->Next = node->Next;
				}
				
				if ( node == _end)
				{
					_end = node->Prev;
				}
				else 
				{
					node->Next->Prev = node->Prev;
				}
				
				delete node;
				--_size;
				
				return returnNode;
			}
			//-------------------------------------------------------------------------------------
			//PROPRIETIES
			SLKNode<T>* begin() const { return _begin; }
			SLKNode<T>* end() const { return _end; }
			int size() const { return _size; }
		};
											  
											  
											  
	}
}

#endif